﻿using UnityEngine;
using Assets.Scripts.LDS;
using System.IO;
using UnityEngine.UI;
using System;
using System.Collections.Generic;
using System.Collections;
#if UNITY_EDITOR
using UnityEditor;
#endif

using SuperPivot;

namespace Assets.Scripts.LDS
{
    public class SsgGenerator : MonoBehaviour
    {
        public GameObject container;
        public string filepath = "SelfData/Result/";
        // Use this for initialization
        void Start()
        {

        }

        // Update is called once per frame
        void Update()
        {
            if (isProcessing)
            {
                StartCoroutine(BatchProcessing());
            }
        }

        public bool genNode = false;
        public void SaveResult(string resultName, GameObject container)
        {
            if (container == null)
            {
                Debug.LogError("container is null!");
                return;
            }

            using (StreamWriter sw = new StreamWriter(filepath + resultName + ".ssg"))
            {
                // catName is "object" line information in DB.ssg 
                sw.WriteLine("3D-FRONTDatabase");
                int modelNum = container.transform.childCount;
                sw.WriteLine("modelCount " + modelNum);
                for (int i = 0; i < modelNum; ++i)
                {
                    //Debug.Log(child.name);
                    Transform child = container.transform.GetChild(i);

                    sw.WriteLine("newModel " + i + " " + child.name);


                    Matrix4x4 transforMatrix = Matrix4x4.TRS(child.position, child.rotation, child.localScale);

                    sw.WriteLine("transform " + string.Format("{0:F6}", transforMatrix.m00) + " " + string.Format("{0:F6}", transforMatrix.m10) + " " + string.Format("{0:F6}", transforMatrix.m20) + " " + string.Format("{0:F6}", transforMatrix.m30) + " "
            + string.Format("{0:F6}", transforMatrix.m01) + " " + string.Format("{0:F6}", transforMatrix.m11) + " " + string.Format("{0:F6}", transforMatrix.m21) + " " + string.Format("{0:F6}", transforMatrix.m31) + " "
            + string.Format("{0:F6}", transforMatrix.m02) + " " + string.Format("{0:F6}", transforMatrix.m12) + " " + string.Format("{0:F6}", transforMatrix.m22) + " " + string.Format("{0:F6}", transforMatrix.m32) + " "
            + string.Format("{0:F6}", transforMatrix.m03) + " " + string.Format("{0:F6}", transforMatrix.m13) + " " + string.Format("{0:F6}", transforMatrix.m23) + " " + string.Format("{0:F6}", transforMatrix.m33));
                }

                if (genNode)
                {
                    SceneSemGraph ssg = Scene.Instance.getSsg();

                    // save nodes in format: nodeId,nodeType,nodeName,inEdgeNodeList,outEdgeNodeList
                    sw.Write("nodeNum " + ssg.m_nodeNum + "\n");
                    for (int i = 0; i < ssg.m_nodeNum; i++)
                    {
                        sw.Write(i + "," + ssg.m_nodes[i].nodeType + "," + ssg.m_nodes[i].nodeName + ","
                            + Util.GetIntString(ssg.m_nodes[i].inEdgeNodeList, " ") + ","
                            + Util.GetIntString(ssg.m_nodes[i].outEdgeNodeList, " ") + "\n");
                    }

                    // save edges in format: edgeId,startId endId
                    sw.Write("edgeNum " + ssg.m_edgeNum + "\n");
                    for (int i = 0; i < ssg.m_edgeNum; i++)
                    {
                        sw.Write(i + "," + ssg.m_edges[i].sourceNodeId + "," + ssg.m_edges[i].targetNodeId + "\n");
                    }


                }
                else
                {
                    sw.WriteLine("nodeNum 0");
                    sw.WriteLine("edgeNum 0");

                }

            }

            Debug.Log(container.name + " saved as " + filepath + resultName + ".ssg");




        }

        public void saveModels(GameObject c)
        {
            foreach (Transform child in c.transform)
            {
                // change pivot: seems it just make the children's position don't change, only change the parents'.
                //SuperPivot.API.SetPivotPosition(child, getCenter(child));
                PrefabUtility.SaveAsPrefabAsset(child.gameObject, @"Assets/Resources/Prefabs/generatePrefabs/" + child.name + ".prefab");
            }
            Debug.Log(c.transform.childCount + " models pivot saved!");
        }
        public void changePivot(GameObject c)
        {
            //getCenter(container.transform);
            foreach (Transform child in c.transform)
            {
                // change pivot: seems it just make the children's position don't change, only change the parents'.
                SuperPivot.API.SetPivotPosition(child, getCenter(child).Item1);
                //PrefabUtility.SaveAsPrefabAsset(child.gameObject, @"Assets/Resources/Prefabs/generatePrefabs/" + child.name + ".prefab");
            }
            Debug.Log(c.transform.childCount + "models pivot adjusted!");
        }

        (Vector3, bool) getCenter(Transform obj)
        {
            if (obj.GetComponent<Renderer>() != null)
            {
                return (obj.GetComponent<Renderer>().bounds.center, true);
            }
            else if (obj.childCount > 0)
            {
                int cnt = 0;
                Vector3 cen = new Vector3(0, 0, 0);
                foreach (Transform subObj in obj)
                {
                    var tmp = getCenter(subObj);
                    if (tmp.Item2)
                    {
                        cen += tmp.Item1;
                        cnt++;
                    }
                }
                if (cnt > 0)
                {
                    return (cen / cnt, true);
                }
            }
            return (new Vector3(), false);
        }

        public string PrefabPth = "/Assets/Resources/Prefabs/generatePrefabs/";

        private bool isProcessing = false;
        public void BatchProcess()
        {
            isProcessing = true;
        }
        private IEnumerator BatchProcessing()
        {
            isProcessing = false;

            List<string> allSSGFileNames = new List<string>();
            using (StreamReader sr = new StreamReader(@"SelfData\SceneDB\scene_list_release.txt"))//Change to my_ scene_ list_ release.txt Using front data set
            {
                string currLine;
                currLine = sr.ReadLine();
                if (currLine.Contains("SceneNum"))
                {
                    int sceneNum = Util.StringToIntegerList(currLine, "SceneNum ")[0];
                    // load all file names
                    for (int i = 0; i < sceneNum; i++)
                    {
                        currLine = sr.ReadLine();
                        string ssgFileName = currLine;//Change to my_ SSGs use the front data set
                        allSSGFileNames.Add(ssgFileName);
                    }
                }
            }


            SceneSemGraph chairSsg = new SceneSemGraph(@"SelfData\Result\chairs_raw.ssg");
            var metaChair = chairSsg.m_graphMetaScene.m_metaModellList;

            int countmodel = 0;
            foreach (var ssgName in allSSGFileNames)
            {
                string ssgFileName = @"SelfData\SceneDB\SSGs\" + ssgName + ".ssg";
                SceneSemGraph ssg = new SceneSemGraph(ssgFileName);

               

                if (ssg.m_graphMetaScene.m_metaModellList.Count == countmodel)
                {
                    Debug.Log("=============》Processing: " + ssgFileName);

                    //Debug.Log("processing: " + ssgName);
                    ScriptProcessor.Instance.Process("ls " + ssgName);
                    while (ProcessText.IsChanged)
                    {
                        yield return new WaitForSeconds(0f);
                    }
                    changePivot(ModelsManager.container);
                    saveModels(ModelsManager.container);
                    SaveResult(ssgName, ModelsManager.container);

                    var _ssg = new SceneSemGraph(filepath + ssgName + ".ssg");
                    var meta = _ssg.m_graphMetaScene.m_metaModellList;
                    for (int i = 0; i < meta.Count; ++i)
                    {
                        if (meta[i].catName == "chair")
                        {
                            // 随机一个NSM椅子
                            int ran = Util.GenRandomInt(0, metaChair.Count);
                            meta[i].name = metaChair[ran].name;

                            // transform中：scale重置，其他值赋值
                            Vector3 pos = meta[i].transformation.GetPosition();
                            pos.y = metaChair[ran].transformation.GetPosition().y;
                            meta[i].transformation = Matrix4x4.TRS(pos, meta[i].transformation.GetRotation(), metaChair[ran].transformation.GetScale());

                        }
                    }
                    Debug.Log("saved: " + filepath + ssgName + ".ssg");

                    _ssg.saveGraph(filepath + ssgName + ".ssg");
                }
                countmodel = ssg.m_graphMetaScene.m_metaModellList.Count;
            }


        }

        public void ReplaceChairs()
        {
            isProcessing = false;

            List<string> allSSGFileNames = new List<string>();
            using (StreamReader sr = new StreamReader(@"SelfData\SDB.txt"))//Change to my_ scene_ list_ release.txt Using front data set
            {
                string currLine;
                currLine = sr.ReadLine();
                if (currLine.Contains("SceneNum"))
                {
                    int sceneNum = Util.StringToIntegerList(currLine, "SceneNum ")[0];
                    // load all file names
                    for (int i = 0; i < sceneNum; i++)
                    {
                        currLine = sr.ReadLine();
                        string ssgFileName = currLine;//Change to my_ SSGs use the front data set
                        allSSGFileNames.Add(ssgFileName);
                    }
                }
            }

            SceneSemGraph chairSsg = new SceneSemGraph(Params.resultDirectory + "chairs_raw.ssg");
            var metaChair = chairSsg.m_graphMetaScene.m_metaModellList;

            Dictionary<string, int> cntt = new Dictionary<string, int>();

            foreach (var ssgName in allSSGFileNames)
            {

                string ssgFileName = Params.resultDirectory + ssgName + ".ssg";

                if (File.Exists(ssgFileName))
                {
                    SceneSemGraph ssg = new SceneSemGraph(ssgFileName);

                    var meta = ssg.m_graphMetaScene.m_metaModellList;
                    for (int i = 0; i < meta.Count; ++i)
                    {
                        if (meta[i].catName == "chair")
                        {
                            // 随机一个NSM椅子
                            int ran = Util.GenRandomInt(0, metaChair.Count);
                            meta[i].name = metaChair[ran].name;

                            // transform中：scale重置，其他值赋值
                            Vector3 pos = meta[i].transformation.GetPosition();
                            pos.y = metaChair[ran].transformation.GetPosition().y;
                            meta[i].transformation = Matrix4x4.TRS(pos, meta[i].transformation.GetRotation(), metaChair[ran].transformation.GetScale());
                            Debug.Log("processing: " + ssgName);

                            if (!cntt.ContainsKey(metaChair[ran].name))
                            {
                                cntt[metaChair[ran].name] = 1;
                            }
                            else
                            {
                                cntt[metaChair[ran].name] += 1;
                            }
                        }
                    }

                    ssg.saveGraph(ssgFileName);
                }
            }

            using (StreamWriter sr = new StreamWriter(@"SelfData\logChair.txt"))
            {
                sr.WriteLine(cntt.Count);
                foreach (var i in cntt)
                {
                    sr.WriteLine(i.Key + ":" + i.Value);
                }
            }
        }

        public void DrawBounds()
        {
            // 自己写的测试工具，并非执行过程中代码
            //Destroy(gm);
            GameObject gm = new GameObject("pointsL");
            foreach (Transform child in container.transform)
            {
                var pl = LayoutPlanner.origin_planes[child.name];
                Debug.Log(child.transform.position + " " + child.transform.rotation.eulerAngles + " " + child.transform.localScale);
                Debug.Log(child.position + " " + child.rotation.eulerAngles + " " + child.localScale);
                foreach (Vector3 tt in pl)
                {
                    var wewe = child.TransformPoint(tt);
                    var wewe2 = child.transform.TransformPoint(tt);
                    Debug.Log(tt);
                    //Debug.Log(wewe);
                    //Debug.Log(wewe2);

                    GameObject t = GameObject.CreatePrimitive(PrimitiveType.Sphere);
                    t.transform.position = wewe;
                    t.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);

                    t.transform.parent = gm.transform;
                }
            }
        }
    }




#if UNITY_EDITOR
    [CustomEditor(typeof(SsgGenerator))]
    public class SsgGenerator_Editor : Editor
    {
        public SsgGenerator Target;

        private void Awake()
        {
            Target = (SsgGenerator)target;
        }


        public override void OnInspectorGUI()
        {

            Undo.RecordObject(Target, Target.name);

            base.OnInspectorGUI();

            if (Utility.GUIButton("Save", UltiDraw.DarkGrey, UltiDraw.White))
            {
                Target.SaveResult(Target.container.transform.name + "_raw", Target.container);
            }

            if (Utility.GUIButton("Adjust Pivot", UltiDraw.DarkGrey, UltiDraw.White))
            {
                Target.changePivot(Target.container);
            }
            if (Utility.GUIButton("Save Models", UltiDraw.DarkGrey, UltiDraw.White))
            {
                Target.saveModels(Target.container);
            }
            if (Utility.GUIButton("Batch", UltiDraw.DarkGrey, UltiDraw.White))
            {
                Target.BatchProcess();
            }

            //if (Utility.GUIButton("ProcessChairs", UltiDraw.DarkGrey, UltiDraw.White))
            //{
            //    Target.ReplaceChairs();
            //}

            if (Utility.GUIButton("DrawBounds", UltiDraw.DarkGrey, UltiDraw.White))
            {
                Target.DrawBounds();
            }

            if (GUI.changed)
            {
                EditorUtility.SetDirty(Target);
            }

        }
    }
#endif



}